#include <iostream>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <arpa/inet.h>
#include <qbytearray.h>

#include <tws_debugging.h>
#include "xinfomatmactypeparser.h"

//#define _DEBUGING_MAC_

const char DEFAULT_DEVICE[] = "eth0";

XInfomatMacTypeParser::XInfomatMacTypeParser() :
    m_result(INFOMAT_RESULT_OK)
{
}

XInfomatMacTypeParser::~XInfomatMacTypeParser()
{
}

void XInfomatMacTypeParser::getResource(QByteArray in_datagram)
{
    char* data = new char[in_datagram.size()];
    memcpy(data, in_datagram.data(), in_datagram.size());
    assert(INFOMAT_CONFIG_PROTOCOL == *data);

    STInfomatMacType* tmpdata = reinterpret_cast<STInfomatMacType*> (data);
	memcpy (&m_macType, tmpdata, sizeof(STInfomatMacType));
    
	if (NULL!=data)
	{
		delete data;
		data = NULL;
	}
	tmpdata = NULL;

#ifdef _DEBUGING_MAC_
    DEBUG("MacType  : checking ...");
    DEBUG("Pass in Data, After Conversion");
    DEBUG("data size: %0d", in_datagram.size());
    DEBUG("protocol : %0x", m_macType.head.protocol);
    DEBUG("type     : %0d", m_macType.head.type);
    DEBUG("size     : %0d", m_macType.head.size);
    DEBUG("result   : %0d", m_macType.head.result);
    DEBUG("command  : %0d", m_macType.head.command);
    DEBUG("mac      : %s", m_macType.mac);
#endif

    m_macType.head.result = INFOMAT_RESULT_OK; //initialized

    switch (m_macType.head.command)
    {
        case INFOMAT_COMMAND_READ:
            read();
            break;

        case INFOMAT_COMMAND_WRITE:
            write();
            break;

        default:
            DEBUG("XMacTypeParser: no such command");
            m_result = INFOMAT_RESULT_ERR;
            break;
    }

    return;
}

void XInfomatMacTypeParser::read()
{
    struct ifreq ifr;
    memset(&ifr, 0, sizeof(ifr));

    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd < 0)
    {
        DEBUG("Create Socket [Fail]");
        m_result = INFOMAT_RESULT_ERR;
        return;
    }

    strcpy(ifr.ifr_name, DEFAULT_DEVICE);
    int ret = ioctl(fd, SIOCGIFHWADDR, &ifr);
    if (ret != 0)
    {
        DEBUG("Mac Reading: ioctl error");
        m_result = INFOMAT_RESULT_ERR;
    }

    memcpy(m_macType.mac, ifr.ifr_hwaddr.sa_data, 6);

#ifdef _DEBUGING_MAC_
    for (int i=0; i<6; i++)
    {
        DEBUG("Read in Mac Address...");
        DEBUG("BTYE:%02d\t [%02x]",i, *(m_macType.mac+i));
    }
#endif

    close(fd);
    return;
}

void XInfomatMacTypeParser::write()
{
    struct ifreq ifr;
    memset(&ifr, 0, sizeof(ifr));

    ifr.ifr_addr.sa_family = AF_INET;
    strncpy(ifr.ifr_name, DEFAULT_DEVICE, IFNAMSIZ - 1);
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    ioctl(fd, SIOCGIFHWADDR, &ifr);

    char passwd[] = "\xfe\xed\xac\x1d\xbe\xef";

    memcpy((unsigned char*) ifr.ifr_hwaddr.sa_data, passwd, 6);
    ioctl(fd, SIOCSIFHWADDR, &ifr);

    DEBUG("Setting Mac: %.2X:%.2X:%.2X:%.2X:%.2X:%.2X", ifr.ifr_hwaddr.sa_data[0],
            ifr.ifr_hwaddr.sa_data[1], ifr.ifr_hwaddr.sa_data[2], ifr.ifr_hwaddr.sa_data[3],
            ifr.ifr_hwaddr.sa_data[4], ifr.ifr_hwaddr.sa_data[5]);

    memcpy((unsigned char*) ifr.ifr_hwaddr.sa_data, m_macType.mac, 6);
    DEBUG("Setting Mac: %.2X:%.2X:%.2X:%.2X:%.2X:%.2X", ifr.ifr_hwaddr.sa_data[0],
            ifr.ifr_hwaddr.sa_data[1], ifr.ifr_hwaddr.sa_data[2], ifr.ifr_hwaddr.sa_data[3],
            ifr.ifr_hwaddr.sa_data[4], ifr.ifr_hwaddr.sa_data[5]);

    if (0 != ioctl(fd, SIOCSIFHWADDR, &ifr))
    {
        m_result = INFOMAT_RESULT_ERR;
        DEBUG("ioctl error");
    } 
	else
    {
        if (0 != ioctl(fd, SIOCGIFFLAGS, &ifr))
            DEBUG("can not get ifc flags");
    }

    return;
}

QByteArray XInfomatMacTypeParser::getOutDatagram()
{
    m_macType.head.result = m_result;
    char* tmpdata = reinterpret_cast<char*> (&m_macType);
	QByteArray outdata = QByteArray(tmpdata, sizeof(m_macType));

#ifdef _DEBUGING_MAC_OVER
	DEBUG("MacType: Send out data Checking");
	DEBUG("Original Data...");
	DEBUG("bytes:%02x", m_macType.head.protocol);
	DEBUG("bytes:%02x", m_macType.head.type);
	DEBUG("bytes:%02x", m_macType.head.size);
	DEBUG("bytes:%02x", m_macType.head.result);
	DEBUG("bytes:%02x", m_macType.head.command);
	
	for (int i=0; i<6; i++)
		DEBUG("bytes:%02x", *(m_macType.mac+i));

	DEBUG("Send out data:");
	for (int i=0; i<outdata.size(); ++i)
	{
		DEBUG("Byte outdata:%02d : %02x", i, *(outdata.data()+i));
	}
#endif
	return outdata;
}
